﻿using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Mongoose.Windows
{
    /// <summary>
    /// An class allowing to manage matrix animation.
    /// </summary>
    public class MatrixAnimation : MatrixAnimationBase
    {
        public Matrix? From
        {
            get { return (Matrix?)GetValue(FromProperty); }
            set { SetValue(FromProperty, value); }
        }

        // Using a DependencyProperty as the backing store for From.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FromProperty =
            DependencyProperty.Register("From", typeof(Matrix?), typeof(MatrixAnimation), new PropertyMetadata(null));

        public Matrix? To
        {
            get { return (Matrix?)GetValue(ToProperty); }
            set { SetValue(ToProperty, value); }
        }

        // Using a DependencyProperty as the backing store for To.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ToProperty =
            DependencyProperty.Register("To", typeof(Matrix?), typeof(MatrixAnimation), new PropertyMetadata(null));

        /// <summary>
        /// Initializes a new instance of the <see cref="MatrixAnimation"/> class.
        /// </summary>
        public MatrixAnimation()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MatrixAnimation"/> class.
        /// </summary>
        /// <param name="fromValue">From value.</param>
        /// <param name="toValue">To value.</param>
        /// <param name="duration">The duration.</param>
        public MatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration)
        {
            From = fromValue;
            To = toValue;
            Duration = duration;
        }


        /// <summary>
        /// When implemented in a derived class, creates a new instance of the <see cref="T:System.Windows.Freezable" /> derived class.
        /// </summary>
        /// <returns>
        /// The new instance.
        /// </returns>
        protected override Freezable CreateInstanceCore()
        {
            return new MatrixAnimation();
        }

        /// <summary>
        /// When implemented in a derived class, calculates the current value of the animation.
        /// </summary>
        /// <param name="defaultOriginValue">The suggested origin value, used if the animation does not have its own explicitly set start value.</param>
        /// <param name="defaultDestinationValue">The suggested destination value, used if the animation does not have its own explicitly set end value.</param>
        /// <param name="animationClock">An <see cref="T:System.Windows.Media.Animation.AnimationClock" /> that generates the <see cref="P:System.Windows.Media.Animation.Clock.CurrentTime" /> or <see cref="P:System.Windows.Media.Animation.Clock.CurrentProgress" /> used by the host animation.</param>
        /// <returns>
        /// The value this animation believes should be the current value for the property.
        /// </returns>
        protected override Matrix GetCurrentValueCore(Matrix defaultOriginValue, Matrix defaultDestinationValue, AnimationClock animationClock)
        {
            var result = Matrix.Identity;

            if (animationClock.CurrentProgress != null)
            {
                var currentProgress = animationClock.CurrentProgress.Value;
                var from = From ?? defaultOriginValue;
                var to = To ?? defaultDestinationValue;

                result = new Matrix(
                        ((to.M11 - from.M11) * currentProgress) + from.M11,
                        ((to.M12 - from.M12) * currentProgress) + from.M12,
                        ((to.M21 - from.M21) * currentProgress) + from.M21,
                        ((to.M22 - from.M22) * currentProgress) + from.M22,
                        ((to.OffsetX - from.OffsetX) * currentProgress) + from.OffsetX,
                        ((to.OffsetY - from.OffsetY) * currentProgress) + from.OffsetY);

                return result;
            }

            return result;
        }
    }
}
